/*
 * @Author: NingJian
 * @Date: 2021-08-24 11:14:57
 * @LastEditTime: 2021-09-14 17:49:26
 * @LastEditors: NingJian
 * @Description: 
 * @FilePath: /musesdk/src/musesdk.cpp
 * 
 */
#include <musesdk/musesdk.h>
#include "pcie/pcie.h"
#ifndef __linux__
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif

#include <iostream>
#include "utils/utils.h"

static CPcieComm cpc;

static ModelInfo mi;

namespace musesdk
{
    using namespace std;

    /**
 * @description:  连接muse设备
 * @param {*}
 * @return {*} 
 */
    bool MuseConnect()
    {
        if (cpc.pcie_is_open())
            return true;
        return cpc.pcie_open() > 0 ? true : false;
    }

    bool MuseIsConnected()
    {
        return cpc.pcie_is_open();
    }

    /**
 * @description: 
 * @param {string} model_path  模型目录路径
 * @param {bool} full 是否下发全部层
 * @param {int} layel 起始层，当 full = false 生效
 * @return {*}
 */
    bool MuseLoadModel(std::string model_path, bool full, int layel)
    {
        fs::path mp(model_path);
        if (!exists(mp))
            return false;
        fs::path mp_conf = mp;
        mp_conf /= "confs";
        int layers_numbers = 0;
        for (fs::directory_iterator end, ite(mp_conf); ite != end; ++ite)
        {
            if (!is_directory(status(ite->path())))
            {
                if (ite->path().extension().string() == ".txt")
                {
                    ++layers_numbers;
                }
            }
        }

        if (layers_numbers <= 0)
            return false;

        mi.layers_numbers = layers_numbers;
        mi.path = model_path;

        if (!full)
        {
            write_signle_model(cpc, mp, layel, mi);
        }
        else
        {
            write_full_model(cpc, mp, mi);
        }

        return true;
    }

    /**
 * @description: 运行推理
 * @param {uint8_t *} in_data  推理的输入数据
 * @param {size_t} len_data    输入数据长度
 * @return {*}
 */
    bool MuseRunPrediction(uint8_t *in_data, size_t len_data)
    {
        if (len_data != mi.input_size)
            return false;
        cpc.pcie_write(mi.input_address, in_data, len_data);
        return true;
    }

    /**
 * @description:  获取推理结果
 * @param {uint8_t *} out_data  推理结果数据
 * @param {size_t} &len_data    数据长度
 * @return {*}
 */
    bool MuseGetResult(uint8_t *out_data, size_t &len_data)
    {
        UINT len = mi.output_size;
        len_data = cpc.pcie_read(mi.output_address, out_data, len);
        return true;
    }

    /**
 * @description:  关闭muse
 * @param {*}
 * @return {*}
 */
    bool MuseDisconnect()
    {
        cpc.pcie_close();
        return true;
    }

    /**
 * @description: 
 * @param {uint8_t *} in_data
 * @param {size_t} write_len
 * @param {size_t} addr
 * @return {*}
 */
    size_t MuseWriteMem(uint8_t *in_data, size_t write_len, size_t addr)
    {
        return cpc.pcie_write(addr, in_data, write_len);
    }

    /**
 * @description: 
 * @param {uint8_t *} out_data
 * @param {size_t} read_len
 * @param {size_t} addr
 * @return {*}
 */
    size_t MuseReadMem(uint8_t *out_data, size_t read_len, size_t addr)
    {
        UINT len = read_len;
        return cpc.pcie_read(addr, out_data, len);
    }

    /**
 * @description: 
 * @param {uint8_t *} in_data
 * @param {size_t} write_len
 * @param {size_t} addr
 * @return {*}
 */
    size_t MuseWriteReg(uint8_t *in_data, size_t write_len, size_t addr)
    {
        return cpc.pcie_write(addr, in_data, write_len, "user");
    }

    /**
 * @description: 
 * @param {uint8_t *} out_data
 * @param {size_t} read_len
 * @param {size_t} addr
 * @return {*}
 */
    size_t MuseReadReg(uint8_t *out_data, size_t read_len, size_t addr)
    {
        UINT len = read_len;
        return cpc.pcie_read(addr, out_data, len, "user");
    }

}